/*
 * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
 * Copyright (C) 2024, 2025  Mio
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
module app.cmds.artwork;

import pd.configuration: Config;

/**
 * Download specified artworks.
 *
 * The expected format of *args* is: `["pixiv_down", "artwork", "id1", ...]`
 *
 * Params:
 *   args = The arguments passed to pixiv_down.
 *   config = pixiv_down configuration
 * Returns: 0 on success, non-zero on error
 */
public int artworkHandle(string[] args, const ref Config config)
{
   import std.algorithm.searching : all, find;
   import std.conv : ConvException, to;
   import std.getopt : getopt, GetOptOption = config;
   import std.stdio : stderr, stdout;
   import pd.error_cache;
   import pd.pixiv;
   import pd.pixiv_downloader;
   import app.util : sleep;

   // When an exception occurs.
   string[] invalidArtworks;
   // The error message for the invalidArtworks
   // each index in the array matches the ID.
   string[] errorMessages;
   bool groupErrors = false;
   bool forceDownload = false;
   int returnCode = 0;

   /* artwork <id> */
   if (args.length < 2) {
      displayArtworkHelp();
      return 1;
   }

   auto helpInformation = getopt(args,
      GetOptOption.passThrough,
      "group-errors", &groupErrors,
      "force|f", &forceDownload,
      );

   if (helpInformation.helpWanted) {
      displayArtworkHelp();
      return 0;
   }

   ErrorCache errorCache = loadErrorCache();
   scope(exit) save(errorCache);

   string[] ids = find!(isValidID)(args);
   foreach(id; ids) {
      try {
         ArtworkInfo info = fetchArtworkInfo(id, config);
         downloadArtwork(info, config, forceDownload);
	 errorCache.artworks.removeKey(id);
      } catch (PixivJSONException pje)  {
         if (groupErrors) {
            invalidArtworks ~= id;
            errorMessages ~= pje.msg;
         } else {
            stderr.writefln("Error: Failed to fetch and download ID '%s'", id);
            stderr.writeln(pje.msg);
        }

         errorCache.artworks.insert(id);
         continue;
      }

      sleep(1, 5);
   }

   if (groupErrors && 0 < invalidArtworks.length) {
      stderr.writeln("Failed to download the following IDs:");
      foreach (index, id; invalidArtworks) {
         stderr.writefln("   %s - %s", id, errorMessages[index]);
      }
   }

   return returnCode;
}

void displayArtworkHelp()
{
   import std.stdio : stderr;

   stderr.writefln(
      "pixiv_down artwork - Download specific artwork(s)\n" ~
      "\nUsage:\tpixiv_down artwork [options] <id> [<additional ids...>]\n" ~
      "\nYou can download one or more artworks via this command.  Any\n" ~
      "artworks that fail to download are mentioned after attempting to\n" ~
      "download, you can change this to only print at the end by using the\n" ~
      "--group-errors option.\n" ~
      "\nOptions:\n" ~
      "   -f, --force-download\tOverwrite existing downloads.\n" ~
      "   --group-errors      \tDisplay errors at the end instead.\n" ~
      "\nExamples:\n" ~
      "\n  Download a single artwork:\n" ~
      "       pixiv_down artwork id\n" ~
      "\n  Download multiple artworks and display failed IDs at the end:\n" ~
      "       pixiv_down artwork --group-errors id1 id2\n");
}


private:

bool isValidID(const(char)[] id) {
   import std.algorithm.searching : all;
   import std.ascii : isDigit;

   return id.all!(isDigit);
}
